package com.itcs.app.pay.swiftpass;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.itcs.app.pay.PayPlatformAdapter;
import com.itcs.app.pay.model.QrcodeFilterRes;
import com.itcs.app.pay.model.QrcodePayModel;
import com.itcs.app.pay.model.QrcodePayRes;
import com.itcs.app.pay.model.TradePayModel;
import com.itcs.app.pay.model.TradePayRes;
import com.itcs.app.pay.swiftpass.properties.SwiftpassProperties;
import com.itcs.app.pay.swiftpass.service.SwiftpassService;
import com.itcs.app.pay.swiftpass.util.PaymentKit;
import com.itcs.app.util.HttpUtil;
import com.itcs.app.util.ParamMap;
import com.itcs.app.util.PayChannelCode;

/**
 * 威富通支付平台
 * 
 * @author LiuPeng
 * @date 2018年3月18日
 * 
 */
@Component
public class SwiftpassPayPlatform implements PayPlatformAdapter {

	private Log logger = LogFactory.getLog(getClass());
	
	@Autowired
	private SwiftpassService swiftpassService;
	
	@Autowired
	private SwiftpassProperties config;
	
	public final static String TYPE = "swiftpass";

	@Override
	public String getPayPlatformType() {
		return TYPE;
	}
	
	@Override
	public QrcodeFilterRes qrcodeFilter(HttpServletRequest request, String payChannelCode) {
		ParamMap param = ParamMap.init(request);
		String redirectUrl = "";
		String state = request.getParameter("state");
		Map<String, String> map = new HashMap<>();
		if (PayChannelCode.微信支付.equals(payChannelCode)) {
			String code = request.getParameter("code");
			if (null == code) {
				redirectUrl = config.getWxAuthUri().replace("APPID", config.getWxAppId());
				redirectUrl = redirectUrl.replace("STATE", getParam(param));// 传参数
				try {
					redirectUrl = redirectUrl.replace("ENCODED_URL", URLEncoder.encode(config.getAuthRedirectUrl(), "UTF-8"));
				} catch (UnsupportedEncodingException e) {
				}
				return new QrcodeFilterRes("redirect:" + redirectUrl);
			} else {
				String openId = getOpenId(config, code);
				map.put("openId", openId);
				
				ParamMap originalMap = ParamMap.newMap();
				originalMap.put("openId", openId);
				originalMap.putAll(string2Map(state));
				logger.info("威富通微信主扫获取原始信息===" + originalMap.toString());
				return new QrcodeFilterRes(originalMap, map);
			}
		}else if (PayChannelCode.支付宝支付.equals(payChannelCode)) {
			String authCode = request.getParameter("auth_code");
			if (null == authCode) {
				redirectUrl = config.getAliAuthUri().replace("APPID", config.getAliAppId());// 支付宝服务窗APPID
				redirectUrl = redirectUrl.replace("SCOPE", "auth_base");// 静默授权
				redirectUrl = redirectUrl.replace("STATE", getParam(param));// 传参数
				try {
					redirectUrl = redirectUrl.replace("ENCODED_URL", URLEncoder.encode(config.getAuthRedirectUrl(), "UTF-8"));
				} catch (UnsupportedEncodingException e) {
				}
				return new QrcodeFilterRes("redirect:" + redirectUrl);
			} else {
				String openId = getUserId(config, authCode);
				map.put("openId", openId);
				
				ParamMap originalMap = ParamMap.newMap();
				originalMap.put("openId", openId);
				originalMap.putAll(string2Map(state));
				logger.info("威富通支付宝主扫获取原始信息===" + originalMap.toString());
				return new QrcodeFilterRes(originalMap, map);
			}
		} else {
			return null;
		}
	}
	
	@Override
	public QrcodePayRes qrcode(QrcodePayModel qrcodePayModel) {
		return swiftpassService.pay(qrcodePayModel);
	}

	@Override
	public TradePayRes tradePay(TradePayModel tradePayModel) {
		logger.info("被扫支付订单信息===="+tradePayModel.toString());
		//支付结果
		JSONObject jsonObject = swiftpassService.swipeCardPay(tradePayModel);
		TradePayRes res = new TradePayRes(TradePayRes.RESCODE_FAILED, TradePayRes.PAY_FAILED);
		if (TradePayRes.RESCODE_SUCCESS.equals(jsonObject.getString("status"))) {
			res.setRescode(TradePayRes.RESCODE_SUCCESS);
			if (TradePayRes.RESCODE_SUCCESS.equals(jsonObject.getString("result_code"))) {
				res.setPayStatus(TradePayRes.PAY_SUCCESS);
				res.setChannelOrderNo(jsonObject.getString("out_transaction_id"));
				res.setPlatformOrderNo(jsonObject.getString("transaction_id"));
				res.setOpenid(jsonObject.getString("openid"));
				return res;//支付成功直接返回
			}
		}
		//需要查询获知是否支付成功
		String needQuery = jsonObject.getString("need_query");
		if (null == needQuery || "Y".equals(needQuery)) {
			for(int i = 0; i < 7; i++) {
				//6次查询结束撤销订单
				if (i == 6) {
					try {
						Thread.sleep(15000L);
					} catch (InterruptedException e) {
					}
					swiftpassService.cancelOrder(tradePayModel);
					res.setPayStatus(TradePayRes.PAY_FAILED);
					return res;
				}
				JSONObject queryOrder = swiftpassService.queryOrder(tradePayModel.getTradeNo(), "bs");
				String tradeState = queryOrder.getString("trade_state");
				if ("SUCCESS".equals(tradeState)) {
					res.setPayStatus(TradePayRes.PAY_SUCCESS);
					res.setChannelOrderNo(queryOrder.getString("out_transaction_id"));
					res.setPlatformOrderNo(queryOrder.getString("transaction_id"));
					res.setOpenid(queryOrder.getString("openid"));
					return res;//支付成功直接返回
				}
				//如果交易已关闭则不再查询
				if ("CLOSED".equals(tradeState)) {
					res.setPayStatus(TradePayRes.PAY_FAILED);
					swiftpassService.cancelOrder(tradePayModel);//交易关闭撤销订单
					return res;//支付失败直接返回
				}
				try {
					Thread.sleep(5000L);
				} catch (InterruptedException e) {
				}
			}
		}
		return res;
	}

	
	/**
	 * 获取微信openid
	 * @param code
	 * @param param
	 * @return
	 */
	private String getOpenId(SwiftpassProperties config, String code) {
		
		String openIdUrl = "";
		openIdUrl = config.getWxTokenUrl().replace("APPID", config.getWxAppId());
		openIdUrl = openIdUrl.replace("SERECT", config.getWxAppSerect());
		openIdUrl = openIdUrl.replace("CODE", code);
		
		String result = HttpUtil.httpRequest(openIdUrl, "POST", "");
		JSONObject json = JSONObject.parseObject(result);
		String openId = json.getString("openid");
		return openId;
	}
	
	/**
	 * 获取支付宝user_id
	 * @param config
	 * @param authCode
	 * @param param
	 * @return
	 */
	private String getUserId(SwiftpassProperties config, String authCode){
	
		Map<String, String> m = new HashMap<>();
		m.put("app_id", config.getAliAppId());
		m.put("method", "alipay.system.oauth.token");
		m.put("charset", "utf-8");
		m.put("sign_type", "RSA2");
		m.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		m.put("grant_type", "authorization_code");
		m.put("code", authCode);
		String params = PaymentKit.packageSign(m, false);
		String sign = "";
		try {
			sign = AlipaySignature.rsa256Sign(params, config.getAliAppPrivateKey(), "utf-8");
		} catch (AlipayApiException e) {
		}
		m.put("sign", sign);
		String ret = HttpUtil.doPost(config.getAliGateway(), m);
		JSONObject jsonObject = JSONObject.parseObject(ret);
		JSONObject authReponst = jsonObject.getJSONObject("alipay_system_oauth_token_response");
		String openId = authReponst.getString("user_id");
		return openId;
	}
	
	/**
	 * 拼接STATE参数
	 * @param map
	 * @return
	 */
	private String getParam(ParamMap map) {
		StringBuilder sb = new StringBuilder();
		Set<String> keySet = map.keySet();
		for (String key : keySet) {
			sb.append(key).append("_");
			sb.append(map.get(key).toString());
			sb.append("-");
		}
		String str = sb.toString();
		return str.substring(0, str.length() - 1);
	}
	
	/**
	 * 参数构造为map
	 * @param s
	 * @return
	 */
	private Map<String, String> string2Map(String s) {
		String[] arr = s.split("-");
		Map<String,String> map = new HashMap<>();
		String[] split = null;
		for (String ar : arr) {
			split = ar.split("_");
			map.put(split[0].trim(), split[1].trim());
		}
		return map;
	}
}
